(function () {
  const STORAGE_KEY = 'todo-items-v1';

  /** @type {{id:string,title:string,completed:boolean}[]} */
  let items = load();
  let currentFilter = 'all'; // 'all' | 'active' | 'completed'

  const els = {
    newInput: document.getElementById('new-input'),
    addBtn: document.getElementById('add-btn'),
    list: document.getElementById('todo-list'),
    filters: document.querySelectorAll('[data-filter]'),
    countAll: document.getElementById('count-all'),
    countActive: document.getElementById('count-active'),
    countCompleted: document.getElementById('count-completed'),
  };

  // -- Init --
  render();
  bindEvents();

  function bindEvents() {
    els.addBtn.addEventListener('click', () => {
      addItem(els.newInput.value.trim());
    });
    els.newInput.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') addItem(els.newInput.value.trim());
    });

    els.clearCompleted.addEventListener('click', () => {
      items = items.filter((it) => !it.completed);
      persist();
      render();
    });

    els.filters.forEach((btn) => {
      btn.addEventListener('click', () => {
        currentFilter = btn.dataset.filter || 'all';
        els.filters.forEach((b) => b.classList.toggle('is-active', b === btn));
        render();
      });
    });

    // Delegate list events
    els.list.addEventListener('click', (e) => {
      const target = /** @type {HTMLElement} */ (e.target);
      const root = target.closest('.todo-item');
      if (!root) return;
      const id = root.dataset.id;

      if (target.matches('[data-action="toggle"]')) {
        toggleCompleted(id);
      } else if (target.matches('[data-action="delete"]')) {
        deleteItem(id);
      } else if (target.matches('[data-action="edit"]')) {
        enterEdit(root, id);
      } else if (target.matches('[data-action="save"]')) {
        const input = root.querySelector('.todo-item__input');
        saveEdit(id, input?.value.trim() || '');
      } else if (target.matches('[data-action="cancel"]')) {
        exitEdit(root);
      }
    });

    els.list.addEventListener('dblclick', (e) => {
      const target = /** @type {HTMLElement} */ (e.target);
      const root = target.closest('.todo-item');
      if (!root) return;
      const id = root.dataset.id;
      if (target.classList.contains('todo-item__title')) {
        enterEdit(root, id);
      }
    });

    els.list.addEventListener('keydown', (e) => {
      const target = /** @type {HTMLElement} */ (e.target);
      const root = target.closest('.todo-item');
      if (!root) return;
      const id = root.dataset.id;

      if (target.classList.contains('todo-item__input')) {
        if (e.key === 'Enter') {
          e.preventDefault();
          saveEdit(id, /** @type {HTMLInputElement} */ (target).value.trim());
        } else if (e.key === 'Escape') {
          e.preventDefault();
          exitEdit(root);
        }
      }
    });
  }

  // -- Actions --
  function addItem(title) {
    if (!title) {
      els.newInput.focus();
      return;
    }
    const item = { id: cryptoRandomId(), title, completed: false };
    items.unshift(item);
    els.newInput.value = '';
    persist();
    render();
  }

  function deleteItem(id) {
    items = items.filter((it) => it.id !== id);
    persist();
    render();
  }

  function toggleCompleted(id) {
    const it = items.find((i) => i.id === id);
    if (!it) return;
    it.completed = !it.completed;
    persist();
    render();
  }

  function enterEdit(root, id) {
    root.classList.add('editing');
    const it = items.find((i) => i.id === id);
    const input = root.querySelector('.todo-item__input');
    if (input && it) {
      input.value = it.title;
      /** @type {HTMLInputElement} */ (input).focus();
      /** @type {HTMLInputElement} */ (input).select();
    }
  }

  function exitEdit(root) {
    root.classList.remove('editing');
  }

  function saveEdit(id, title) {
    const it = items.find((i) => i.id === id);
    if (!it) return;
    it.title = title || it.title;
    persist();
    render();
  }

  // -- Render --
  function render() {
    const filtered = items.filter((it) => {
      if (currentFilter === 'active') return !it.completed;
      if (currentFilter === 'completed') return it.completed;
      return true;
    });

    els.list.innerHTML = filtered.map(renderItem).join('');

    // Stats
    const all = items.length;
    const active = items.filter((i) => !i.completed).length;
    const completed = all - active;
    els.countAll.textContent = `总数: ${all}`;
    els.countActive.textContent = `未完成: ${active}`;
    els.countCompleted.textContent = `已完成: ${completed}`;
  }

  function renderItem(it) {
    return `
      <li class="todo-item ${it.completed ? 'completed' : ''}" data-id="${it.id}">
        <div class="todo-item__label todo-item__view">
          <input type="checkbox" ${it.completed ? 'checked' : ''} aria-label="完成状态" data-action="toggle" />
          <span class="todo-item__title">${escapeHtml(it.title)}</span>
        </div>
        <div class="todo-item__actions todo-item__view">
          <button class="todo-item__btn" data-action="edit">编辑</button>
          <button class="todo-item__btn" data-action="delete">删除</button>
        </div>
        <div class="todo-item__edit">
          <input class="todo-item__input" type="text" aria-label="编辑输入" />
          <div class="todo-item__actions">
            <button class="todo-item__btn" data-action="save">保存</button>
            <button class="todo-item__btn" data-action="cancel">取消</button>
          </div>
        </div>
      </li>
    `;
  }

  // -- Storage --
  function load() {
    try {
      const raw = localStorage.getItem(STORAGE_KEY);
      if (!raw) return [];
      const list = JSON.parse(raw);
      if (!Array.isArray(list)) return [];
      return list.filter((x) => x && typeof x.title === 'string').map((x) => ({
        id: String(x.id || cryptoRandomId()),
        title: String(x.title || ''),
        completed: Boolean(x.completed),
      }));
    } catch {
      return [];
    }
  }

  function persist() {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(items));
  }

  // -- Utils --
  function escapeHtml(str) {
    return String(str)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  }

  function cryptoRandomId() {
    // Prefer crypto if available
    if (window.crypto?.randomUUID) return window.crypto.randomUUID();
    const arr = new Uint32Array(4);
    if (window.crypto?.getRandomValues) {
      window.crypto.getRandomValues(arr);
      return Array.from(arr).map((n) => n.toString(16)).join('');
    }
    return Math.random().toString(16).slice(2) + Date.now().toString(16);
  }
})();